package com.groupbuying.sysconfig.service.impl.ali;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;

import com.groupbuying.sysconfig.constants.AliAuthLoginConstants;
import com.groupbuying.sysconfig.domain.SysconfigPlatformInfoDO;
import com.groupbuying.sysconfig.intercepter.ConfigContextHandler;
import com.groupbuying.sysconfig.service.ali.AliAuthLoginService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 支付宝用户授权认证和授权手机号解密信息接口
 * @Auther: YangMeng
 * @Date: 2019/10/16 14:45
 **/
@Service
public class AliAuthLoginServiceImpl implements AliAuthLoginService {
    private static final Logger logger = LoggerFactory.getLogger(AliAuthLoginServiceImpl.class);

    /**
     * 用户认证授权获取alipayUserId和accessToken（公有）
     * @param authCode
     * @return map
     * @throws Exception
     */
    @Override
    public Map<String, String> aliGetUserIdAccessCodeByAuthCode (String authCode) throws Exception {
        AlipaySystemOauthTokenResponse result=this.doGetResponseByAuthCode(authCode);
        logger.info("获取result的值：{}", JSON.toJSONString(result));
        if (result != null) {
            Map<String,String> map=new HashMap<>();
            map.put("alipayUserId", result.getUserId());
            map.put("accessToken", result.getAccessToken());
            return map;
        }
        return null;

    }

    /**
     * 支付宝用户授权手机号解密信息接口
     * @param params
     * @return map
     */
    @Override
    public Map<String, String> aliDecodeUserEncryptedData (Map<String, String> params) {
        String encryptedData = params.get("encryptedData");
        logger.info("需要解密信息：encryptedData:{}, 支付宝SDK基础配置信息：params:{}", params.get("encryptedData"), params);
        //1、获取验签和解密所需要的参数
        Map<String, String> openapiResult = JSON.parseObject(encryptedData,
                new TypeReference<Map<String, String>>() {
                }, Feature.OrderedField);
        logger.info("支付宝验签和解签所需要的参数: openapiResult:{}", openapiResult);
        String signType = ConfigContextHandler.getSysconfigInfo().getSignType();
        String charset = ConfigContextHandler.getSysconfigInfo().getCharset();
        String encryptType = ConfigContextHandler.getSysconfigInfo().getEncryptType();
        logger.info("支付宝验签和解签所需要的参数：signType:{}, charset:{}, encryptType:{}",
                ConfigContextHandler.getSysconfigInfo().getSignType(),
                ConfigContextHandler.getSysconfigInfo().getCharset(),
                ConfigContextHandler.getSysconfigInfo().getEncryptType());
        String sign = openapiResult.get("sign");
        String content = openapiResult.get("response");
        //如果密文的
        boolean isDataEncrypted = !content.startsWith("{");
        logger.info("校验参数值:{}", isDataEncrypted);
        boolean signCheckPass = false;
        //2、验签
        String signContent = content;
        String signVeriKey = ConfigContextHandler.getSysconfigInfo().getPublicKey();
        String decryptKey = ConfigContextHandler.getSysconfigInfo().getDecryptKey();
        //如果是加密的报文则需要在密文的前后添加双引导
        if (isDataEncrypted) {
            signContent = "\"" + signContent + "\"";
            logger.info("查看是否是密文：{}",signContent);
        }
        try {
            signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
            logger.info("支付宝验签signCheckPass:{}", signCheckPass);
        } catch (AlipayApiException e) {
            logger.error("支付宝解密用户手机号验证签名异常:{}", e.getMessage());
            e.printStackTrace();
        }
        if (!signCheckPass) {
            //验签不通过（异常或者报文被篡改），终止流程（不需要做解密）
            logger.error("支付宝解密用户手机号验证签名失败");
            return null;
        }
        //3、解密
        String plainData = null;
        Map<String, String> result = new HashMap<>();
        if (isDataEncrypted) {
            try {
                plainData = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset);
                logger.info("支付宝解密: plainData:{}", plainData);
            } catch (AlipayApiException e) {
                //解密异常
                logger.info("支付宝用户手机号解密异常");
                return null;
            }
        } else {
            plainData = content;
        }
        result = JSON.parseObject(plainData, Map.class);
        logger.info("最后返回信息解密信息:{}", plainData);
        if ("10000".equals(result.get("code"))) {
            return result;
        } else {
            logger.error("解密信息错误，错误信息:{}", result);
            return null;
        }
    }

    /**
     * 用户认证授权获取alipayUserId和accessToken（私有）
     * @param authCode
     * @return response
     * @throws Exception
     */
    private AlipaySystemOauthTokenResponse doGetResponseByAuthCode(String authCode) throws Exception{
        if (authCode == null && "".equals(authCode)) {
            logger.error("参数:authCode, 不能为空");
        }
        logger.info("前端传递的参数：authCode:{}", authCode);
        //根据前端传递的唯一标识和类型获取配置文件数据
        SysconfigPlatformInfoDO sysconfigPlatformInfoDO = ConfigContextHandler.getSysconfigInfo();
        //获取数据配置文件
        AlipayClient alipayClient = new DefaultAlipayClient(sysconfigPlatformInfoDO.getGateUrl(), sysconfigPlatformInfoDO.getAppId(),
                sysconfigPlatformInfoDO.getAppSecret(), sysconfigPlatformInfoDO.getFormat(), sysconfigPlatformInfoDO.getCharset(),
                sysconfigPlatformInfoDO.getPublicKey(), sysconfigPlatformInfoDO.getSignType());
        logger.info("获取阿里配置信息：url:{}, appId:{}, appSecret:{}, format:{}, charset:{}, publicKey:{}, signType:{}",sysconfigPlatformInfoDO.getGateUrl(), sysconfigPlatformInfoDO.getAppId(),
                sysconfigPlatformInfoDO.getAppSecret(), sysconfigPlatformInfoDO.getFormat(), sysconfigPlatformInfoDO.getCharset(),
                sysconfigPlatformInfoDO.getPublicKey(), sysconfigPlatformInfoDO.getSignType());

        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType(AliAuthLoginConstants.AUTHORIZATION_CODE);
        request.setCode(authCode);
        AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
        if (response.isSuccess()){
            logger.info("用户认证授权成功");
            return response;
        } else {
            logger.info("用户认证授权失败");
        }
        return null;
    }
}

